package com.canaan.business.common.helper;

import cn.hutool.core.util.StrUtil;
import com.canaan.business.common.enums.inOutStock.StrategyTypeEnum;
import com.canaan.business.common.enums.storehouse.StorehouseStockStatusEnum;
import com.canaan.business.domain.agv.AgvTaskDispatch;
import com.canaan.business.domain.basic.StockStrategy;
import com.canaan.business.domain.basic.WmsStorehouseLocation;
import com.canaan.business.domain.bill.Tray;
import com.canaan.business.domain.bill.TrayDetail;
import com.canaan.business.domain.storehouse.WmsStorehouseStock;
import com.canaan.business.domain.vo.WmsStorehouseStockVo;
import com.canaan.business.service.agv.IAgvTaskDispatchService;
import com.canaan.business.service.basic.IStockStrategyService;
import com.canaan.business.service.bill.ITrayDetailService;
import com.canaan.business.service.bill.ITrayService;
import com.canaan.business.service.inOutStock.IAdjustLocationBillService;
import com.canaan.business.service.storehouse.IStorehouseStockStrategyService;
import com.canaan.business.service.storehouse.IWmsStockInStockStrategyService;
import com.canaan.business.service.storehouse.IWmsStorehouseStockService;
import com.canaan.common.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

@Component
@Slf4j
public class EmptyStockHelper {
    @Autowired
    IWmsStorehouseStockService storehouseStockService;
    @Autowired
    IStockStrategyService stockStrategyService;
    @Autowired
    IStorehouseStockStrategyService storehouseStockStrategyService;
    @Autowired
    private BeanHelper beanHelper;
    @Autowired
    private IAdjustLocationBillService adjustLocationBillService;
    @Autowired
    WmsStoreHouseLocationHelper locationHelper;
    @Autowired
    ITrayDetailService trayDetailService;
    @Autowired
    IAgvTaskDispatchService agvTaskDispatchService;
    @Autowired
    ITrayService trayService;
    /**
     * 锁
     */
    private final ReentrantLock reentrantLock=new ReentrantLock();

    /**
     * 分析入库情况
     */
    public WmsStorehouseLocation analyseInStock(String billNo,String productNo,Boolean checkProduct,Boolean isEmptyTray){
        String logId = UUID.randomUUID().toString();
        log.info("开始分析入库情况,日志编号:{},billNo:{},productNo:{},checkProduct:{},isEmptyTray:{}",logId,billNo,productNo,checkProduct,isEmptyTray);
        //是否需要调库
        boolean isNeedAdjustStock = false;
        WmsStorehouseLocation destLocation = null;
        WmsStorehouseLocation adjustSourceLocation = null;
        WmsStorehouseStock adjustSourceStock=null;
        WmsStorehouseLocation adjustDestLocation=null;
        WmsStorehouseStock adjustDestStock=null;
        boolean result=false;
        try {
            //加锁，超过10秒报异常
            result = reentrantLock.tryLock(10000, TimeUnit.MILLISECONDS);
            if (result) {
                WmsStorehouseStockVo stock = null;
                StrategyTypeEnum strategyTypeEnum=isEmptyTray?StrategyTypeEnum.EMPTY_SHELF:StrategyTypeEnum.PRODUCT;
                StockStrategy stockStrategy = stockStrategyService.selectInStockDefaultStrategy(strategyTypeEnum.getCode());
                if (stockStrategy == null) {
                    stock = storehouseStockStrategyService.selectEmptyLocationByMinRowMinColumn();
                } else {
                    IWmsStockInStockStrategyService inStockStrategyService = (IWmsStockInStockStrategyService) beanHelper.getBean(stockStrategy.getClassName());
                    if (inStockStrategyService == null) {
                        throw new RuntimeException("入库策略" + stockStrategy.getClassName() + "不存在");
                    }
                    List<WmsStorehouseStockVo> stockVos = null;
                    if(checkProduct||isEmptyTray) {
                       stockVos=  inStockStrategyService.getEmptyStocks();
                    }
                    else{
                       stockVos= storehouseStockStrategyService.selectPreStorageEmpWmsStorehouseStockListMinRowMinColumn();
                    }
                    for (WmsStorehouseStockVo item : stockVos) {
                        if (StrUtil.equalsIgnoreCase("0", item.getIsInner())) {
                            //不存在关联里库
                            if(StringUtils.isEmpty(item.getInnerLocation())){
                                stock=item;
                                break;
                            }
                            //检验物料
                            if(checkProduct||isEmptyTray) {
                                //检验里库的物料是否一致
                                if (checkInnerLocationProduction(item.getInnerLocation(), productNo, isEmptyTray)) {
                                    stock = item;
                                    break;
                                }
                            }
                            else{
                                //检验里库的托盘的Erp出库单据叫是否一致
                                if (checkInnerLocationBill(item.getInnerLocation(),billNo)) {
                                    stock = item;
                                    break;
                                }
                            }
                        } else {
                            if(StringUtils.isEmpty(item.getInnerLocation())){
                                stock=item;
                                break;
                            }
                            WmsStorehouseStock refStock=storehouseStockService.selectWmsStorehouseStockByLocationNo(item.getInnerLocation());
                            if(refStock==null){
                                stock=item;
                                break;
                            }
                            if(!(StorehouseStockStatusEnum.NORMAL.getCode().equals(refStock.getStatus()))){
                                continue;
                            }
                            //外库存在容器，则跳过
                            if(StringUtils.isNotEmpty(refStock.getContainerNo())){
                                continue;
                            }
                            stock = item;
                            break;
                        }
                    }
                }
                if (stock == null) {
                    throw new RuntimeException("成品仓不存在空库位");
                }
                destLocation = locationHelper.getLocationByNo(stock.getStorehouseLocationNo());

                //库位为里库
                if ("1".equals(destLocation.getIsInner())) {
                    WmsStorehouseLocation refLocation = locationHelper.getLocationByNo(destLocation.getInnerLocation());
                    if (refLocation == null) {
                        throw new RuntimeException("库位" + destLocation.getNo() + "关联库位不存在");
                    }
                    WmsStorehouseStock refStock = storehouseStockService.selectWmsStorehouseStockByLocationNo(refLocation.getNo());
                    if (refStock != null && StringUtils.isNotEmpty(refStock.getContainerNo())) {
                        adjustSourceLocation = refLocation;
                        adjustSourceStock = refStock;
                        isNeedAdjustStock = true;
                    }
                } else {
                    if (StringUtils.isNotEmpty(destLocation.getInnerLocation())) {
                        WmsStorehouseLocation refLocation = locationHelper.getLocationByNo(destLocation.getInnerLocation());
                        if (refLocation != null) {
                            WmsStorehouseStock refStock = storehouseStockService.selectWmsStorehouseStockByLocationNo(refLocation.getNo());

                            if (refStock != null && StringUtils.isEmpty(refStock.getContainerNo())
                                    && StorehouseStockStatusEnum.NORMAL.getCode().equals(refStock.getStatus())) {
                                destLocation = refLocation;
                            }
                        }
                    }
                }
                //锁定目标库位
                WmsStorehouseStock destStock = storehouseStockService.selectWmsStorehouseStockByLocationNo(destLocation.getNo());
                if (destStock == null) {
                    throw new RuntimeException("库位" + destLocation.getNo() + "不存在库存数据");
                }
                destStock.setStatus(StorehouseStockStatusEnum.LOCK.getCode());
                storehouseStockService.updateWmsStorehouseStock(destStock);
                //是否需要调库
                if (isNeedAdjustStock) {
                    adjustDestLocation = adjustLocationBillService.generateAdjustDestLocation(adjustSourceLocation.getNo(),
                            adjustSourceLocation.getIsInner(), adjustSourceLocation.getInnerLocation());
                    if (adjustDestLocation != null) {
                        adjustDestStock = storehouseStockService.selectWmsStorehouseStockByLocationNo(adjustDestLocation.getNo());
                        if (adjustDestStock != null) {
                            adjustDestStock.setStatus(StorehouseStockStatusEnum.LOCK.getCode());
                            storehouseStockService.updateWmsStorehouseStock(adjustDestStock);
                            adjustSourceStock.setStatus(StorehouseStockStatusEnum.LOCK.getCode());
                            storehouseStockService.updateWmsStorehouseStock(adjustSourceStock);
                        }
                    }
                }
            } else {
                throw new RuntimeException("get lock time out");
            }
        }catch(Exception e) {
            throw new RuntimeException(e.getMessage());
        }
        finally {
            reentrantLock.unlock();
        }
        //创建调库单
        if(isNeedAdjustStock) {
            if (adjustDestStock != null) {
                adjustLocationBillService.generateAdjustLocationBill(adjustSourceStock, adjustSourceLocation, adjustDestStock, adjustDestLocation, billNo);
            }
        }
        log. info("分析入库情况完成,日志编号:{},billNo:{},productNo:{},checkProduct:{},isEmptyTray:{},result:{},destLocation:{}",logId,billNo,productNo,checkProduct,isEmptyTray,result,destLocation);
        return destLocation;
    }

    /**
     * 检验里库物料是否相同
     */
    private boolean checkInnerLocationProduction(String innerLocation,String productNo,Boolean isEmptyTray){
        WmsStorehouseStock innerStock = storehouseStockService.selectWmsStorehouseStockByLocationNo(innerLocation);
        if (innerStock == null) {
            return false;
        }
        //里库库存已经不是NORMAL状态,同时有AGV任务起点是该里库
        if(!(StorehouseStockStatusEnum.NORMAL.getCode().equals(innerStock.getStatus()))){
            return false;
            //TODO 出库单会锁定库位,但是出库接驳位全部被占用,此时AGV任务不会生成
//            List<AgvTaskDispatch> agvTaskDispatches=agvTaskDispatchService.selectAgvTaskDispatchListByStartPoint(innerStock.getStorehouseLocationNo());
//            if(agvTaskDispatches!=null&&agvTaskDispatches.size()!=0) {
//                return false;
//            }
        }
        if(isEmptyTray){
            if(StringUtils.isNotEmpty(innerStock.getContainerNo())){
                if(StringUtils.isEmpty(innerStock.getTrayNo())){
                    return true;
                }
                else{
                    return false;
                }
            }
            //判断是否有对应的agv任务
            List<AgvTaskDispatch> agvTaskDispatches = agvTaskDispatchService.selectAgvTaskDispatchListByEndPoint(innerLocation);
            if(agvTaskDispatches==null|agvTaskDispatches.size()==0){
                return true;
            }
            AgvTaskDispatch agvTaskDispatch = agvTaskDispatches.get(0);
            if(StringUtils.isNotEmpty(agvTaskDispatch.getShelfNo())&&StringUtils.isEmpty(agvTaskDispatch.getTrayNo())){
                return true;
            }
            return false;
        }
        else{
            //排除空料架
            if(StringUtils.isNotEmpty(innerStock.getContainerNo())&&StringUtils.isEmpty(innerStock.getTrayNo())){
                return false;
            }
            if(StringUtils.isNotEmpty(innerStock.getTrayNo())) {
                TrayDetail trayDetailQuery = new TrayDetail();
                trayDetailQuery.setTrayNo(innerStock.getTrayNo());
                trayDetailQuery.setDelFlag("0");
                List<TrayDetail> trayDetails = trayDetailService.selectTrayDetailList(trayDetailQuery);
                if (trayDetails == null) {
                    return false;
                }
                List<TrayDetail> tmpDetails = trayDetails.stream().filter(O -> StrUtil.equalsIgnoreCase(productNo, O.getProductNo())).collect(Collectors.toList());
                //里库的物料一致
                return tmpDetails.size() != 0;
            }
            else {
                //判断是否有对应的agv任务
                List<AgvTaskDispatch> agvTaskDispatches = agvTaskDispatchService.selectAgvTaskDispatchListByEndPoint(innerLocation);
                if(agvTaskDispatches==null|agvTaskDispatches.size()==0){
                    return true;
                }
                AgvTaskDispatch agvTaskDispatch = agvTaskDispatches.get(0);
                if(StringUtils.isEmpty(agvTaskDispatch.getTrayNo())){
                    return false;
                }
                TrayDetail trayDetailQuery = new TrayDetail();
                trayDetailQuery.setTrayNo(agvTaskDispatches.get(0).getTrayNo());
                trayDetailQuery.setDelFlag("0");
                List<TrayDetail> trayDetails = trayDetailService.selectTrayDetailList(trayDetailQuery);
                if (trayDetails == null || trayDetails.size() == 0) {
                    return false;
                }
                List<TrayDetail> tmpDetailsByAgvTrayNo = trayDetails.stream().filter(O -> StrUtil.equalsIgnoreCase(productNo, O.getProductNo())).collect(Collectors.toList());
                //里库的物料一致
                return tmpDetailsByAgvTrayNo.size() != 0;
            }
        }
    }

    /**
     * 检验里库物料是否相同
     */
    private boolean checkInnerLocationBill(String innerLocation,String billNo){
        WmsStorehouseStock innerStock = storehouseStockService.selectWmsStorehouseStockByLocationNo(innerLocation);
        if (innerStock == null) {
            return false;
        }
        //里库库存已经不是NORMAL状态,同时有AGV任务起点是该里库
        if(!(StorehouseStockStatusEnum.NORMAL.getCode().equals(innerStock.getStatus()))){
            List<AgvTaskDispatch> agvTaskDispatches=agvTaskDispatchService.selectAgvTaskDispatchListByStartPoint(innerStock.getStorehouseLocationNo());
            if(agvTaskDispatches!=null&&agvTaskDispatches.size()!=0) {
                return false;
            }
        }
        //排除空料架
        if(StringUtils.isNotEmpty(innerStock.getContainerNo())&&StringUtils.isEmpty(innerStock.getTrayNo())){
            return false;
        }
        if(StringUtils.isNotEmpty(innerStock.getTrayNo())) {
            Tray tray = trayService.selectTrayByTrayNo(innerStock.getTrayNo());
            if (tray ==null||StringUtils.isEmpty(tray.getErpInBillNo())) {
                return false;
            }
            //里库的单据号一致
            return billNo.equals(tray.getErpOutBillNo());
        }
        else {
            //判断是否有对应的agv任务
            List<AgvTaskDispatch> agvTaskDispatches = agvTaskDispatchService.selectAgvTaskDispatchListByEndPoint(innerLocation);
            if(agvTaskDispatches==null|agvTaskDispatches.size()==0){
                return true;
            }
            AgvTaskDispatch agvTaskDispatch = agvTaskDispatches.get(0);
            if(StringUtils.isEmpty(agvTaskDispatch.getTrayNo())){
                return false;
            }
            Tray tray = trayService.selectTrayByTrayNo(agvTaskDispatch.getTrayNo());
            if (tray ==null||StringUtils.isEmpty(tray.getErpInBillNo())) {
                return false;
            }
            //里库的单据号一致
            return billNo.equals(tray.getErpOutBillNo());
        }
    }

    /**
     * 生成调库
     */
    @Transactional(rollbackFor = Exception.class)
    public void generateAdjustLocation(String locationNo,String isInner,String innerLocation,String billNo){
        WmsStorehouseLocation adjustSourceLocation= locationHelper.getLocationByNo(locationNo);
        WmsStorehouseStock adjustSourceStock=storehouseStockService.selectWmsStorehouseStockByLocationNo((locationNo));
        WmsStorehouseLocation adjustDestLocation=null;
        WmsStorehouseStock adjustDestStock=null;
        WmsStorehouseLocation adjustSourceInnerLocation=null;
        WmsStorehouseStock adjustSourceInnerStock=null;
        boolean result=false;
        try {
            //加锁，超过10秒报异常
            result = reentrantLock.tryLock(10000, TimeUnit.MILLISECONDS);
            if (result) {
                adjustDestLocation=adjustLocationBillService.generateAdjustDestLocation(locationNo,
                        isInner, innerLocation);
                if(adjustDestLocation!=null) {
                    //起点取外库点位
                    adjustSourceInnerLocation= locationHelper.getLocationByNo(adjustSourceLocation.getInnerLocation());
                    adjustSourceInnerStock=storehouseStockService.selectWmsStorehouseStockByLocationNo((adjustSourceLocation.getInnerLocation()));
                    adjustDestStock = storehouseStockService.selectWmsStorehouseStockByLocationNo(adjustDestLocation.getNo());
                    if (adjustDestStock != null) {
                        adjustDestStock.setStatus(StorehouseStockStatusEnum.LOCK.getCode());
                        storehouseStockService.updateWmsStorehouseStock(adjustDestStock);
                        adjustSourceStock.setStatus(StorehouseStockStatusEnum.LOCK.getCode());
                        storehouseStockService.updateWmsStorehouseStock(adjustSourceStock);
                    }
                    if (adjustSourceInnerStock != null && StringUtils.equals(adjustSourceInnerStock.getStatus(), StorehouseStockStatusEnum.NORMAL.getCode())) {
                        adjustSourceInnerStock.setStatus(StorehouseStockStatusEnum.LOCK.getCode());
                        storehouseStockService.updateWmsStorehouseStock(adjustSourceInnerStock);
                    }
                }
            }
            else{
                throw new RuntimeException("get lock time out");
            }
        }catch(Exception e) {
            throw new RuntimeException(e.getMessage());
        }
        finally {
            reentrantLock.unlock();
        }
        if (adjustDestStock != null) {
            adjustLocationBillService.generateAdjustLocationBill(adjustSourceInnerStock, adjustSourceInnerLocation, adjustDestStock, adjustDestLocation, billNo);
        }
    }
}
